/*
 * BTListener.java
 *
 * Created on 29 August 2007, 22:59
 *
 */

package digitrix.network.bt;

import digitrix.fightclub.game.FightClub;
import java.io.DataInputStream;
import java.io.IOException;
import javax.microedition.io.*;

/**
 * 
 * @author Josh
 */
public class BTListener implements Runnable {
    
    private IBTCallback _callback = null; 
    private byte _previousEvent = -1; 
    private DataInputStream _inputStream = null; 
    private int _code = -1; 
    private boolean _running = false; 
    private int _syncError = 0; 
    
    /**
     * Creates a new instance of BTListener
     */
    public BTListener( IBTCallback callback, DataInputStream inputStream ) {
        _callback = callback; 
        _inputStream = inputStream;   
        startListening(); 
    }
    
    private void startListening(){
        _running = true; 
        new Thread( this ).start(); 
    }
    
    public void stop(){
        _running = false;        
        
        if (_inputStream != null){
            try{
                _inputStream.close();
            }
            catch( IOException ioe ){} 
            _inputStream = null; 
        }                        
    }
    
    public boolean isAlive(){
        return _running; 
    }
    
    public void run(){
        
        while( _running ){
            try{
                // read the next signal from a remote player
                // this will block until there is data to read
                byte evt = _inputStream.readByte();                
                
                BTManager.printDebugInfo( this, "run", "Event has come in; event id: " + evt ); 
                
                // handle the event accordingly 
                if( evt == BTManager.EVT_ACK )
                    evt = _previousEvent; 
                else
                    _previousEvent = evt; 
                
                switch( evt ){
                    // handle methods with no associated data
                    case BTManager.EVT_ACCEPT:                                        
                    case BTManager.EVT_DECLINE:                    
                    case BTManager.EVT_END:                    
                    case BTManager.EVT_FIGHT:
                    case BTManager.EVT_GAME_OVER:
                    case BTManager.EVT_PAUSE:                    
                    case BTManager.EVT_RESTART:
                    case BTManager.EVT_SYNC:
                    case BTManager.EVT_READY:
                    case BTManager.EVT_LAG_TEST_REQ:
                    case BTManager.EVT_LAG_TEST_RES: 
                    case BTManager.EVT_LOCAL_LAG_TEST_FINISHED:{
                        _callback.btEvent( evt, 0 ); 
                        break; 
                    }                    
                    case BTManager.EVT_GAME_DATA:
                    case BTManager.EVT_SYNC_ROUND_OVER: 
                    case BTManager.EVT_SYNC_TIME: {
                        // get the code
                        int code = _inputStream.readInt(); 
                        // get keystate 
                        int ks = _inputStream.readInt(); 
                        
                        // if code is greater than what our current code is then proceed, otherwise disgard and increment 
                        // out of sync counter (_syncError) 
                        if( _code <= code ){
                            _code = code; // remember the current code 
                            _callback.btEvent( BTManager.EVT_GAME_DATA, ks ); 
                        }
                        else{
                            // TODO: handle this! - ie get the games to pause and sync up with all the data 
                            BTManager.printDebugInfo( this, "run", "incrementing sync error; sync error is now " + _syncError ); 
                            _syncError++; 
                        }
                        
                        break; 
                    }
                    case BTManager.EVT_REQUEST_FIGHT:{
                        // get player data (as a string)
                        String playerData = _inputStream.readUTF(); 
                        _callback.btFightRequest( playerData ); 
                        break;
                    }
                    case BTManager.EVT_PLAYER_INFO:{
                        // get player data (as a string)
                        String playerData = _inputStream.readUTF(); 
                        _callback.btPlayerDetails( playerData ); 
                        break; 
                    }         
                    case BTManager.EVT_SYNC_DETAILS:{
                        int posX = _inputStream.readInt(); 
                        int posY = _inputStream.readInt(); 
                        int health = _inputStream.readInt(); 
                        
                        _callback.btSyncEvent( posX, posY, health ); 
                        break; 
                    }
                    case BTManager.EVT_SYNC_DATA:{
                        // TODO: 
                        break; 
                    }
                                           
                }
                                                                
            }
            catch(Exception ex){
                // an exception may occur becuase a connection was lost... what to do? 
                // for this assignment I will just close the connection but really what should happen is the 
                // the watcher should report back to the listener and notify them that the player has been 
                // lost then the connection can be closed... This may have to be done... Soon see (probably only matters 
                // for the host). 
                System.err.print( "BTListener.run() :: " + ex.toString() );
                _running = false; // TODO: replace this with a counter ie if 10 exceptions have occured then close connection and notify callback 
            }
        }
        
        BTManager.printDebugInfo( "BTListener", "stop", "Connectoin closed" ); 
    }

    public IBTCallback getCallback() {
        return _callback;
    }

    public void setCallback(IBTCallback callback) {
        this._callback = callback;
    }            
}
